﻿//////////////////////////////////////////////////////////////////
//
// testGeometry.cs
//
// Copyright (c) 2012 Dan Pike.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using Geometry;
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Utilities;

namespace TestEmily
{
   [TestClass]
   public class testGeometry
   {
      [TestMethod]
      public void TestIcosahedron()
      {
         Icosahedron iso = new Icosahedron(13);
         Assert.AreEqual(13, iso.sideLength);
         
         // Check that the distances between adjacent points are all 13
         Point3D[] points = iso.vertices;
         KeyValuePair<int, int>[] adjacentIndex = new KeyValuePair<int, int>[]
         {
            new KeyValuePair<int, int>(0, 1),      // #0
            new KeyValuePair<int, int>(0, 2),      // #1
            new KeyValuePair<int, int>(0, 3),      // #2
            new KeyValuePair<int, int>(0, 4),      // #3
            new KeyValuePair<int, int>(0, 5),      // #4

            new KeyValuePair<int, int>(1, 2),      // #5
            new KeyValuePair<int, int>(2, 3),      // #6
            new KeyValuePair<int, int>(3, 4),      // #7
            new KeyValuePair<int, int>(4, 5),      // #8
            new KeyValuePair<int, int>(5, 1),      // #9

            new KeyValuePair<int, int>(1, 9),      // #10
            new KeyValuePair<int, int>(9, 2),      // #11
            new KeyValuePair<int, int>(2, 10),     // #12
            new KeyValuePair<int, int>(10, 3),     // #13
            new KeyValuePair<int, int>(3, 6),      // #14
            new KeyValuePair<int, int>(6, 4),      // #15
            new KeyValuePair<int, int>(4, 7),      // #16
            new KeyValuePair<int, int>(7, 5),      // #17
            new KeyValuePair<int, int>(5, 8),      // #18
            new KeyValuePair<int, int>(8, 1),      // #19

            new KeyValuePair<int, int>(6, 7),      // #20
            new KeyValuePair<int, int>(7, 8),      // #21
            new KeyValuePair<int, int>(8, 9),      // #22
            new KeyValuePair<int, int>(9, 10),     // #23
            new KeyValuePair<int, int>(10, 6),     // #24

            new KeyValuePair<int, int>(11, 6),     // #25
            new KeyValuePair<int, int>(11, 7),     // #26
            new KeyValuePair<int, int>(11, 8),     // #27
            new KeyValuePair<int, int>(11, 9),     // #28
            new KeyValuePair<int, int>(11, 10)     // #29
         };

         int testIndex = 0;
         adjacentIndex.ToList().ForEach(indexPair =>
            {
               // Calculate the distance between the adjacent sides
               Point3D v1 = points[indexPair.Key];
               Point3D v2 = points[indexPair.Value];
               double distance = Math.Sqrt(Math.Pow(v1.x - v2.x, 2.0) + Math.Pow(v1.y - v2.y, 2.0) + Math.Pow(v1.z - v2.z, 2.0));
               Assert.AreEqual(Math.Round(iso.sideLength, 5), Math.Round(distance, 5), "vertices '{0}' and '{1}' on test #{2}",
                  (char)('a' + indexPair.Key), (char)('a' + indexPair.Value), testIndex);
               ++testIndex;
            });
      }

      [TestMethod]
      public void TestMeshTriangle1()
      {
         MeshTriangle one = MeshTriangle.create();
         Assert.AreEqual(0, one.scale);
         Assert.IsNull(one.leftNeighbour);
         Assert.IsNull(one.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);

         MeshTriangle two = one.addBaseNeighbour();
         Assert.AreEqual(0, one.scale);
         Assert.AreEqual(0, two.scale);
         Assert.IsNull(two.leftNeighbour);
         Assert.IsNull(two.rightNeighbour);
         Assert.AreSame(two.baseNeighbour, one);

         Assert.IsNull(one.leftNeighbour);
         Assert.IsNull(one.rightNeighbour);
         Assert.AreSame(one.baseNeighbour, two);
      }

      [TestMethod]
      public void TestMeshTriangle2()
      {
         MeshTriangle one = MeshTriangle.create();
         Assert.AreEqual(0, one.scale);

         Assert.IsNull(one.leftNeighbour);
         Assert.IsNull(one.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);

         MeshTriangle two = one.addLeftNeighbour();
         Assert.AreEqual(0, one.scale);
         Assert.AreEqual(0, two.scale);
         Assert.IsNull(two.leftNeighbour);
         Assert.IsNull(two.rightNeighbour);
         Assert.AreSame(two.baseNeighbour, one);

         Assert.AreSame(one.leftNeighbour, two);
         Assert.IsNull(one.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);
      }

      [TestMethod]
      public void TestMeshTriangle3()
      {
         MeshTriangle one = MeshTriangle.create();
         Assert.AreEqual(0, one.scale);
         Assert.IsNull(one.leftNeighbour);
         Assert.IsNull(one.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);

         MeshTriangle two = one.addRightNeighbour();
         Assert.AreEqual(0, one.scale);
         Assert.AreEqual(0, two.scale);
         Assert.IsNull(two.leftNeighbour);
         Assert.IsNull(two.rightNeighbour);
         Assert.AreSame(two.baseNeighbour, one);

         Assert.IsNull(one.leftNeighbour);
         Assert.AreSame(one.rightNeighbour, two);
         Assert.IsNull(one.baseNeighbour);
      }

      [TestMethod]
      public void TestMeshTriangleSplit1()
      {
         MeshTriangle one = MeshTriangle.create();
         Assert.AreEqual(0, one.scale);

         MeshTriangle oneChild = one.split();
         Assert.IsNull(oneChild.baseNeighbour);
         Assert.AreSame(oneChild.leftNeighbour, one);
         Assert.IsNull(oneChild.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);
         Assert.IsNull(one.leftNeighbour);
         Assert.AreSame(one.rightNeighbour, oneChild);

         Assert.AreEqual(1, one.scale);
         Assert.AreEqual(1, oneChild.scale);
      }

      [TestMethod]
      public void TestMeshTriangleSplit2()
      {
         MeshTriangle one = MeshTriangle.create();
         MeshTriangle two = one.addBaseNeighbour();
         Assert.AreEqual(0, one.scale);   // they are both full size
         Assert.AreEqual(0, two.scale);
#if DEBUG
         one.name = "one";
         two.name = "two";
#endif

         Assert.AreSame(one.baseNeighbour, two);
         Assert.IsNull(one.leftNeighbour);
         Assert.IsNull(one.rightNeighbour);
         Assert.AreSame(two.baseNeighbour, one);
         Assert.IsNull(two.leftNeighbour);
         Assert.IsNull(two.rightNeighbour);

         // Splitting creates two new triangles
         MeshTriangle oneChild = one.split();
         MeshTriangle twoChild = two.rightNeighbour; // We deduce the other, as the split() function only returns our child, not the recursively-created ones
         Assert.AreEqual(1, one.scale);
         Assert.AreEqual(1, two.scale);
         Assert.AreEqual(1, oneChild.scale);
         Assert.AreEqual(1, twoChild.scale);

         Assert.AreNotSame(oneChild, twoChild);
         Assert.AreNotSame(one, oneChild);
         Assert.AreNotSame(one, twoChild);
         Assert.AreNotSame(two, oneChild);
         Assert.AreNotSame(two, twoChild);

         // Check the adjustments to the existing triangles
         Assert.IsNotNull(oneChild);
         Assert.IsNull(oneChild.baseNeighbour);
         Assert.AreSame(oneChild.leftNeighbour, one);
         Assert.AreSame(oneChild.rightNeighbour, two);
         Assert.AreSame(oneChild, one.rightNeighbour);
         Assert.IsNull(one.baseNeighbour);
         Assert.AreSame(one.rightNeighbour, oneChild);
         Assert.AreSame(one.leftNeighbour, twoChild);

         Assert.IsNotNull(twoChild);
         Assert.IsNull(twoChild.baseNeighbour);
         Assert.AreSame(twoChild.leftNeighbour, two);
         Assert.AreSame(twoChild.rightNeighbour, one);
         Assert.IsNull(two.baseNeighbour);
         Assert.AreSame(two.leftNeighbour, oneChild);
         Assert.AreSame(two.rightNeighbour, twoChild);
      }

      [TestMethod]
      public void TestMeshTriangleSplit3()
      {
      }
   }
}
